﻿/*
 * File Name:               RectangleSimple.cs
 * 
 * Description:             RectangleSimple
 * Author:                  zhangke <kris@zhanng.org>
 * Create Date:             2017/11/25
 */

using UnityEngine;


/// <summary>
// 矩形 与世界坐标平行 
//
// point4|-------------| point3
//       |             | 
//       |             | vertical
//       |             | 
// point1|-------------| point2
//          horizontal
/// </summary>
public struct RectangleSimple
{
    public XNumber xmin;
    public XNumber xmax;
    public XNumber ymin;
    public XNumber ymax;

    public RectangleSimple(XVector2 point1, XVector2 point2, XVector2 point3, XVector2 point4)
    {
        xmin = XIntMath.Min(XIntMath.Min(point1.x, point2.x), XIntMath.Min(point3.x, point4.x));
        xmax = XIntMath.Max(XIntMath.Max(point1.x, point2.x), XIntMath.Max(point3.x, point4.x));
        ymin = XIntMath.Min(XIntMath.Min(point1.y, point2.y), XIntMath.Min(point3.y, point4.y));
        ymax = XIntMath.Max(XIntMath.Max(point1.y, point2.y), XIntMath.Min(point3.y, point4.y));
    }

    public bool CheckIn(XVector2 point)
    {
        return point.x > xmin && point.x < xmax && point.y > ymin && point.y < ymax;
    }

    // 矩形 与世界坐标平行 
    //  c|-------------| d
    //   |             | 
    //   |             | vertical
    //   |             | 
    //  a|-------------| b
    //      horizontal
    public void GetCorners(out XVector2 a, out XVector2 b, out XVector2 c, out XVector2 d)
    {
        a = new XVector2(xmin, ymin);
        b = new XVector2(xmax, ymin);
        c = new XVector2(xmin, ymax);
        d = new XVector2(xmax, ymax);
    }

    /// <summary>
    /// 线段与矩形的交点 存在多个则返回离pos01最近的点
    /// </summary>
    /// <param name="pos01"></param>
    /// <param name="pos02"></param>
    /// <returns></returns>
    public XVector2? getCrossPoint(XVector2 pos01, XVector2 pos02)
    {
        // 这里为了简化计算量 仅计算了交叉线的交点 也就是结果并不处于矩形的边缘 但是应该会符合设计需求
        XVector2 a, b, c, d;
        GetCorners(out a, out b, out c, out d);
        var cross01 = Math2D.Point_Cross_SegmentAndSegment(a, b, pos01, pos02);
        var cross02 = Math2D.Point_Cross_SegmentAndSegment(a, c, pos01, pos02);
        var cross03 = Math2D.Point_Cross_SegmentAndSegment(d, b, pos01, pos02);
        var cross04 = Math2D.Point_Cross_SegmentAndSegment(d, c, pos01, pos02);

        XVector2? ret = null;
        var curDis = XNumber.MaxValue;
        if (cross01.HasValue)
        {
            var _tempDis = XVector2.Distance(cross01.Value, pos01);
            if (_tempDis < curDis)
            {
                curDis = _tempDis;
                ret = cross01;
            }
        }

        if (cross02.HasValue)
        {
            var _tempDis = XVector2.Distance(cross02.Value, pos01);
            if (_tempDis < curDis)
            {
                curDis = _tempDis;
                ret = cross02;
            }
        }

        if (cross03.HasValue)
        {
            var _tempDis = XVector2.Distance(cross03.Value, pos01);
            if (_tempDis < curDis)
            {
                curDis = _tempDis;
                ret = cross03;
            }
        }

        if (cross04.HasValue)
        {
            var _tempDis = XVector2.Distance(cross04.Value, pos01);
            if (_tempDis < curDis)
            {
                curDis = _tempDis;
                ret = cross04;
            }
        }

        return ret;
    }

    /// <summary>
    /// 返回离该点最近的端点
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public XVector2 getNearestPoint(XVector2 pos)
    {
        XVector2 a, b, c, d;
        GetCorners(out a, out b, out c, out d);

        var disA = XVector2.DistanceSquare(a, pos);
        var disB = XVector2.DistanceSquare(b, pos);
        var disC = XVector2.DistanceSquare(c, pos);
        var disD = XVector2.DistanceSquare(d, pos);
        var curDis = disA;
        var curRet = a;
        if (disB < curDis)
        {
            curDis = disB;
            curRet = b;
        }

        if (disC < curDis)
        {
            curDis = disC;
            curRet = c;
        }

        if (disD < curDis)
        {
            curDis = disD;
            curRet = d;
        }

        return curRet;
    }

    public void Draw(XVector2 point)
    {
        Draw(point, Color.white);
    }

    public void Draw(XVector2 point, Color areaColor)
    {
#if UNITY_EDITOR
        XVector2 a, b, c, d;
        GetCorners(out a, out b, out c, out d);

        Debug.DrawLine(a.x0z, b.x0z, areaColor);
        Debug.DrawLine(a.x0z, c.x0z, areaColor);
        Debug.DrawLine(b.x0z, d.x0z, areaColor);
        Debug.DrawLine(c.x0z, d.x0z, areaColor);

        if (point != null)
        {
            if (CheckIn(point))
            {
                Debug.DrawLine(new Vector3((xmin + xmax) / 2, 0, (ymin + ymax) / 2), point.x0z, Color.green);
            }
            else
            {
                Debug.DrawLine(new Vector3((xmin + xmax) / 2, 0, (ymin + ymax) / 2), point.x0z, Color.red);
            }
        }
#endif
    }
}